package com.dhecp.project.flowable.extend;

import com.dhecp.common.utils.StringUtils;
import com.dhecp.core.constant.FlowableConstant;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.flowable.bpmn.model.*;
import org.flowable.editor.language.json.converter.BaseBpmnJsonConverter;
import org.flowable.editor.language.json.converter.BpmnJsonConverterContext;
import org.flowable.editor.language.json.converter.UserTaskJsonConverter;
import org.flowable.editor.language.json.converter.util.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * @ClassName CustomUserTaskJsonConverter
 * @Description TODO
 * @Author alula
 * @Date 2020-05-13 20:43
 */
public class CustomUserTaskJsonConverter extends UserTaskJsonConverter {

    private static final Logger LOGGER = LoggerFactory.getLogger(CustomUserTaskJsonConverter.class);

    static void customFillTypes(Map<String, Class<? extends BaseBpmnJsonConverter>> convertersToBpmnMap, Map<Class<? extends BaseElement>, Class<? extends BaseBpmnJsonConverter>> convertersToJsonMap) {
        fillJsonTypes(convertersToBpmnMap);
        fillBpmnTypes(convertersToJsonMap);
    }

    public static void fillJsonTypes(Map<String, Class<? extends BaseBpmnJsonConverter>> convertersToBpmnMap) {
        convertersToBpmnMap.put(STENCIL_TASK_USER, CustomUserTaskJsonConverter.class);
    }

    public static void fillBpmnTypes(
            Map<Class<? extends BaseElement>, Class<? extends BaseBpmnJsonConverter>> convertersToJsonMap) {
        convertersToJsonMap.put(UserTask.class, CustomUserTaskJsonConverter.class);
    }

    @Override
    protected FlowElement convertJsonToElement(JsonNode elementNode, JsonNode modelNode,
                                               Map<String, JsonNode> shapeMap, BpmnJsonConverterContext converterContext) {
        UserTask task = new UserTask();
        task.setPriority(this.getPropertyValueAsString("prioritydefinition", elementNode));
        String formKey = this.getPropertyValueAsString("formkeydefinition", elementNode);
        JsonNode formReferenceNode;
        //自定义属性
        List<ExtensionAttribute> list = new ArrayList<>();
        if (org.apache.commons.lang3.StringUtils.isNotEmpty(formKey)) {
            task.setFormKey(formKey);
        } else {
            formReferenceNode = this.getProperty("formreference", elementNode);
            if (formReferenceNode != null && formReferenceNode.get("id") != null) {
                String formModelId = formReferenceNode.get("id").asText();
                String formModelKey = converterContext.getFormModelKeyForFormModelId(formModelId);
                if (formModelKey != null) {
                    task.setFormKey(formModelKey);
                } else {
                    String key = formReferenceNode.get("key").asText();
                    if (org.apache.commons.lang3.StringUtils.isNotEmpty(key)) {
                        task.setFormKey(key);
                    }
                }
            }
        }

        task.setValidateFormFields(this.getPropertyValueAsString("formfieldvalidation", elementNode));
        task.setDueDate(this.getPropertyValueAsString("duedatedefinition", elementNode));
        task.setBusinessCalendarName(this.getPropertyValueAsString("calendarname", elementNode));
        task.setCategory(this.getPropertyValueAsString("categorydefinition", elementNode));
        task.setTaskIdVariableName(this.getPropertyValueAsString("taskidvariablename", elementNode));
        formReferenceNode = this.getProperty("usertaskassignment", elementNode);
        if (formReferenceNode != null) {
            JsonNode assignmentDefNode = formReferenceNode.get("assignment");
            if (assignmentDefNode != null) {
                JsonNode typeNode = assignmentDefNode.get("type");
                JsonNode canCompleteTaskNode = assignmentDefNode.get("initiatorCanCompleteTask");
                JsonNode idmDefNode;
                if (typeNode != null && !"static".equalsIgnoreCase(typeNode.asText())) {
                    if ("idm".equalsIgnoreCase(typeNode.asText())) {
                        idmDefNode = assignmentDefNode.get("idm");
                        if (idmDefNode != null && idmDefNode.has("type")) {
                            JsonNode idmTypeNode = idmDefNode.get("type");
                            if (idmTypeNode == null || !"user".equalsIgnoreCase(idmTypeNode.asText()) || !idmDefNode.has("assignee") && !idmDefNode.has("assigneeField")) {
                                if (idmTypeNode != null && "users".equalsIgnoreCase(idmTypeNode.asText()) && (idmDefNode.has("candidateUsers") || idmDefNode.has("candidateUserFields"))) {
                                    this.fillCandidateUsers(idmDefNode, canCompleteTaskNode, task);
                                } else if (idmTypeNode == null || !"groups".equalsIgnoreCase(idmTypeNode.asText()) || !idmDefNode.has("candidateGroups") && !idmDefNode.has("candidateGroupFields")) {
                                    task.setAssignee("$INITIATOR");
                                    this.addExtensionElement("activiti-idm-initiator", String.valueOf(true), task);
                                } else {
                                    this.fillCandidateGroups(idmDefNode, canCompleteTaskNode, task);
                                }
                            } else {
                                this.fillAssigneeInfo(idmDefNode, canCompleteTaskNode, task);
                            }
                        }
                    }
                } else {
                    idmDefNode = assignmentDefNode.get("assignee");
                    if (idmDefNode != null && !idmDefNode.isNull()) {
                        task.setAssignee(idmDefNode.asText());
                    }
                    task.setCandidateUsers(this.getValueAsList("candidateUsers", assignmentDefNode));
                    task.setCandidateGroups(this.getValueAsList("candidateGroups", assignmentDefNode));
                    //存储自定义代理人、候选人、候选组
                    JsonNode customAssigneeNameNode = assignmentDefNode.get("assigneeName");
                    ExtensionAttribute customAssigneeNameAttr =  ExtensionAttributeUtils.generate(FlowableConstant.CUSTOM_ASSIGNEENAME_KEY, (customAssigneeNameNode == null) ? "": customAssigneeNameNode.textValue());
                    if (customAssigneeNameAttr != null){
                        list.add(customAssigneeNameAttr);
                    }
                    //候选人
                    JsonNode customCandidateUsersNode = assignmentDefNode.get("candidateUsers");
                    if(customCandidateUsersNode != null) {
                        ExtensionElement customCandidateUsersElement = new ExtensionElement();
                        customCandidateUsersElement.setName(FlowableConstant.CUSTOM_CANDIDATEUSERS_KEY);
                        customCandidateUsersElement.setNamespacePrefix("custom");
                        customCandidateUsersElement.setNamespace("http://www.fzdhsoft.com/");
                        customCandidateUsersElement.setElementText((customCandidateUsersNode == null) ? "" : customCandidateUsersNode.toString());
                        task.addExtensionElement(customCandidateUsersElement);
                    }
                    //候选组
                    JsonNode customCandidateGroupsNode = assignmentDefNode.get("candidateGroups");
                    if(customCandidateGroupsNode != null) {
                        ExtensionElement customCandidateGroupsElement = new ExtensionElement();
                        customCandidateGroupsElement.setName(FlowableConstant.CUSTOM_CANDIDATEGROUPS_KEY);
                        customCandidateGroupsElement.setNamespacePrefix("custom");
                        customCandidateGroupsElement.setNamespace("http://www.fzdhsoft.com/");
                        customCandidateGroupsElement.setElementText((customCandidateGroupsNode == null) ? "" : customCandidateGroupsNode.toString());
                        task.addExtensionElement(customCandidateGroupsElement);
                    }
                    //end 存储自定义
                    if (org.apache.commons.lang3.StringUtils.isNotEmpty(task.getAssignee()) && !"$INITIATOR".equalsIgnoreCase(task.getAssignee())) {
                        if (canCompleteTaskNode != null && !canCompleteTaskNode.isNull()) {
                            this.addInitiatorCanCompleteExtensionElement(Boolean.valueOf(canCompleteTaskNode.asText()), task);
                        } else {
                            this.addInitiatorCanCompleteExtensionElement(false, task);
                        }
                    } else if (org.apache.commons.lang3.StringUtils.isNotEmpty(task.getAssignee()) && "$INITIATOR".equalsIgnoreCase(task.getAssignee())) {
                        this.addInitiatorCanCompleteExtensionElement(true, task);
                    }
                }
            }
        }
        task.setSkipExpression(this.getPropertyValueAsString("skipexpression", elementNode));
        //设置自定义属性
        Map<String,List<ExtensionAttribute>> attrMap = new HashMap<String,List<ExtensionAttribute>>();
        String customPropertyObj1 = getPropertyValueAsString(FlowableConstant.CUSTOM_DATA_CANDIDATE_ID,elementNode);
        ExtensionAttribute ea1 =  ExtensionAttributeUtils.generate(FlowableConstant.CUSTOM_DATA_CANDIDATE_KEY, StringUtils.isEmpty(customPropertyObj1)? "":customPropertyObj1);
        String customPropertyObj2 = getPropertyValueAsString(FlowableConstant.CUSTOM_AUDIT_FUNCTIONKEY_ID,elementNode);
        ExtensionAttribute ea2 =  ExtensionAttributeUtils.generate(FlowableConstant.CUSTOM_AUDIT_FUNCTIONKEY_KEY,StringUtils.isEmpty(customPropertyObj2)? "":customPropertyObj2);
        String customPropertyObj3 = getPropertyValueAsString(FlowableConstant.CUSTOM_AUDIT_FORMPAGE_ID,elementNode);
        ExtensionAttribute ea3 =  ExtensionAttributeUtils.generate(FlowableConstant.CUSTOM_AUDIT_FORMPAGE_KEY,StringUtils.isEmpty(customPropertyObj3)? "":customPropertyObj3);
        String customPropertyObj4 = getPropertyValueAsString(FlowableConstant.CUSTOM_AUDIT_FUNCTIONEDIT_ID,elementNode);
        ExtensionAttribute ea4 =  ExtensionAttributeUtils.generate(FlowableConstant.CUSTOM_AUDIT_FUNCTIONEDIT_KEY,StringUtils.isEmpty(customPropertyObj4)? "false":customPropertyObj4);
        if (ea1 != null){
            list.add(ea1);
        }
        if (ea2 != null){
            list.add(ea2);
        }
        if (ea3 != null){
            list.add(ea3);
        }
        if (ea4 != null){
            list.add(ea4);
        }
        attrMap.put("CUSTOM-FLOWABLE-EXT",list);
        if (attrMap.size()>0){
            task.setAttributes(attrMap);
        }
        this.convertJsonToFormProperties(elementNode, task);
        return task;
    }

    @Override
    protected void convertElementToJson(ObjectNode propertiesNode, BaseElement baseElement, BpmnJsonConverterContext converterContext){
        UserTask userTask = (UserTask)baseElement;
        String assignee = userTask.getAssignee();
        ObjectNode assignmentValuesNode;
        Map<String, List<ExtensionAttribute>> extensionAttrs = userTask.getAttributes();
        if (org.apache.commons.lang3.StringUtils.isNotEmpty(assignee) || CollectionUtils.isNotEmpty(userTask.getCandidateUsers()) || CollectionUtils.isNotEmpty(userTask.getCandidateGroups())) {
            ObjectNode assignmentNode = this.objectMapper.createObjectNode();
            assignmentValuesNode = this.objectMapper.createObjectNode();
            List<ExtensionElement> idmAssigneeList = (List)userTask.getExtensionElements().get("activiti-idm-assignee");
            List<ExtensionElement> idmAssigneeFieldList = (List)userTask.getExtensionElements().get("activiti-idm-assignee-field");
            if (!CollectionUtils.isNotEmpty(idmAssigneeList) && !CollectionUtils.isNotEmpty(idmAssigneeFieldList) && !CollectionUtils.isNotEmpty((Collection)userTask.getExtensionElements().get("activiti-idm-candidate-user")) && !CollectionUtils.isNotEmpty((Collection)userTask.getExtensionElements().get("activiti-idm-candidate-group"))) {
                assignmentValuesNode.put("type", "static");
                if (org.apache.commons.lang3.StringUtils.isNotEmpty(assignee)) {
                    assignmentValuesNode.put("assignee", assignee);
                    assignmentValuesNode.put("assigneeName", getAssigneeName(FlowableConstant.CUSTOM_ASSIGNEENAME_KEY, extensionAttrs));
                }
                userTask.getExtensionElements();
                ArrayNode candidateArrayNode;
                Iterator var20;
                String candidateGroup;
                ObjectNode candidateNode;
                if (CollectionUtils.isNotEmpty(userTask.getCandidateUsers())) {
                    candidateArrayNode = this.objectMapper.createArrayNode();
                    var20 = userTask.getCandidateUsers().iterator();

                    while(var20.hasNext()) {
                        candidateGroup = (String)var20.next();
                        candidateNode = this.objectMapper.createObjectNode();
                        candidateNode.put("value", candidateGroup);
                        candidateNode.put("name", getCandidateValueName(FlowableConstant.CUSTOM_CANDIDATEUSERS_KEY, userTask.getExtensionElements(), candidateGroup));
                        candidateArrayNode.add(candidateNode);
                    }

                    assignmentValuesNode.set("candidateUsers", candidateArrayNode);
                }

                if (CollectionUtils.isNotEmpty(userTask.getCandidateGroups())) {
                    candidateArrayNode = this.objectMapper.createArrayNode();
                    var20 = userTask.getCandidateGroups().iterator();

                    while(var20.hasNext()) {
                        candidateGroup = (String)var20.next();
                        candidateNode = this.objectMapper.createObjectNode();
                        candidateNode.put("value", candidateGroup);
                        candidateNode.put("name", getCandidateValueName(FlowableConstant.CUSTOM_CANDIDATEGROUPS_KEY, userTask.getExtensionElements(), candidateGroup));
                        candidateArrayNode.add(candidateNode);
                    }

                    assignmentValuesNode.set("candidateGroups", candidateArrayNode);
                }
            } else {
                assignmentValuesNode.put("type", "idm");
                ObjectNode idmNode = this.objectMapper.createObjectNode();
                assignmentValuesNode.set("idm", idmNode);
                List<ExtensionElement> canCompleteList = (List)userTask.getExtensionElements().get("initiator-can-complete");
                if (CollectionUtils.isNotEmpty(canCompleteList)) {
                    assignmentValuesNode.put("initiatorCanCompleteTask", Boolean.valueOf(((ExtensionElement)canCompleteList.get(0)).getElementText()));
                }

                if (org.apache.commons.lang3.StringUtils.isNotEmpty(userTask.getAssignee())) {
                    ObjectNode assigneeNode = this.objectMapper.createObjectNode();
                    assigneeNode.put("id", userTask.getAssignee());
                    idmNode.set("assignee", assigneeNode);
                    idmNode.put("type", "user");
                    this.fillProperty("email", "assignee-info-email", assigneeNode, userTask);
                    this.fillProperty("firstName", "assignee-info-firstname", assigneeNode, userTask);
                    this.fillProperty("lastName", "assignee-info-lastname", assigneeNode, userTask);
                }

                List<ExtensionElement> idmCandidateUserList = (List)userTask.getExtensionElements().get("activiti-idm-candidate-user");
                if (CollectionUtils.isNotEmpty(userTask.getCandidateUsers()) && CollectionUtils.isNotEmpty(idmCandidateUserList) && userTask.getCandidateUsers().size() > 0) {
                    ArrayNode candidateUsersNode = this.objectMapper.createArrayNode();
                    idmNode.set("candidateUsers", candidateUsersNode);
                    idmNode.put("type", "users");
                    Iterator var14 = userTask.getCandidateUsers().iterator();

                    while(var14.hasNext()) {
                        String candidateUser = (String)var14.next();
                        ObjectNode candidateUserNode = this.objectMapper.createObjectNode();
                        candidateUserNode.put("id", candidateUser);
                        candidateUsersNode.add(candidateUserNode);
                        this.fillProperty("email", "user-info-email-" + candidateUser, candidateUserNode, userTask);
                        this.fillProperty("firstName", "user-info-firstname-" + candidateUser, candidateUserNode, userTask);
                        this.fillProperty("lastName", "user-info-lastname-" + candidateUser, candidateUserNode, userTask);
                    }
                }

                List<ExtensionElement> idmCandidateGroupList = (List)userTask.getExtensionElements().get("activiti-idm-candidate-group");
                if (CollectionUtils.isNotEmpty(userTask.getCandidateGroups()) && CollectionUtils.isNotEmpty(idmCandidateGroupList) && userTask.getCandidateGroups().size() > 0) {
                    ArrayNode candidateGroupsNode = this.objectMapper.createArrayNode();
                    idmNode.set("candidateGroups", candidateGroupsNode);
                    idmNode.put("type", "groups");
                    Iterator var26 = userTask.getCandidateGroups().iterator();

                    while(var26.hasNext()) {
                        String candidateGroup = (String)var26.next();
                        ObjectNode candidateGroupNode = this.objectMapper.createObjectNode();
                        candidateGroupNode.put("id", candidateGroup);
                        candidateGroupsNode.add(candidateGroupNode);
                        this.fillProperty("name", "group-info-name-" + candidateGroup, candidateGroupNode, userTask);
                    }
                }
            }

            assignmentNode.set("assignment", assignmentValuesNode);
            propertiesNode.set("usertaskassignment", assignmentNode);
        }

        if (userTask.getPriority() != null) {
            this.setPropertyValue("prioritydefinition", userTask.getPriority(), propertiesNode);
        }

        this.setPropertyValue("skipexpression", userTask.getSkipExpression(), propertiesNode);
        if (org.apache.commons.lang3.StringUtils.isNotEmpty(userTask.getFormKey())) {
            Map<String, String> modelInfo = converterContext.getFormModelInfoForFormModelKey(userTask.getFormKey());
            if (modelInfo != null) {
                assignmentValuesNode = this.objectMapper.createObjectNode();
                assignmentValuesNode.put("id", (String)modelInfo.get("id"));
                assignmentValuesNode.put("name", (String)modelInfo.get("name"));
                assignmentValuesNode.put("key", (String)modelInfo.get("key"));
                propertiesNode.set("formreference", assignmentValuesNode);
            } else {
                this.setPropertyValue("formkeydefinition", userTask.getFormKey(), propertiesNode);
            }
        }

        this.setPropertyValue("formfieldvalidation", userTask.getValidateFormFields(), propertiesNode);
        this.setPropertyValue("duedatedefinition", userTask.getDueDate(), propertiesNode);
        this.setPropertyValue("calendarname", userTask.getBusinessCalendarName(), propertiesNode);
        this.setPropertyValue("categorydefinition", userTask.getCategory(), propertiesNode);
        this.setPropertyValue("taskidvariablename", userTask.getTaskIdVariableName(), propertiesNode);

        //扩展自定义属性
        if (extensionAttrs != null && extensionAttrs.size() > 0) {
            List<ExtensionAttribute> extensionAttributeList1 = extensionAttrs.get(FlowableConstant.CUSTOM_DATA_CANDIDATE_KEY);
            if (extensionAttributeList1 != null && extensionAttributeList1.size() > 0) {
                setPropertyValue(FlowableConstant.CUSTOM_DATA_CANDIDATE_ID, (StringUtils.isEmpty(extensionAttributeList1.get(0).getValue()) ? "": extensionAttributeList1.get(0).getValue()), propertiesNode);
            }
            List<ExtensionAttribute> extensionAttributeList2 = extensionAttrs.get(FlowableConstant.CUSTOM_AUDIT_FUNCTIONKEY_KEY);
            if (extensionAttributeList2 != null && extensionAttributeList2.size() > 0) {
                setPropertyValue(FlowableConstant.CUSTOM_AUDIT_FUNCTIONKEY_ID, (StringUtils.isEmpty(extensionAttributeList2.get(0).getValue()) ? "": extensionAttributeList2.get(0).getValue()), propertiesNode);
            }
            List<ExtensionAttribute> extensionAttributeList3 = extensionAttrs.get(FlowableConstant.CUSTOM_AUDIT_FORMPAGE_KEY);
            if (extensionAttributeList3 != null && extensionAttributeList3.size() > 0) {
                setPropertyValue(FlowableConstant.CUSTOM_AUDIT_FORMPAGE_ID, (StringUtils.isEmpty(extensionAttributeList3.get(0).getValue()) ? "": extensionAttributeList3.get(0).getValue()), propertiesNode);
            }
            List<ExtensionAttribute> extensionAttributeList4 = extensionAttrs.get(FlowableConstant.CUSTOM_AUDIT_FUNCTIONEDIT_KEY);
            if (extensionAttributeList4 != null && extensionAttributeList4.size() > 0) {
                setPropertyValue(FlowableConstant.CUSTOM_AUDIT_FUNCTIONEDIT_ID, (StringUtils.isEmpty(extensionAttributeList4.get(0).getValue()) ? "false": extensionAttributeList4.get(0).getValue()), propertiesNode);
            }
        }
        this.addFormProperties(userTask.getFormProperties(), propertiesNode);
    }

    /**
     * 创建自定义属性
     *
     * @param propertyName  属性名称
     * @param propertyValue 属性值
     */
    private CustomProperty createProperty(String propertyName, String propertyValue) {
        CustomProperty customProperty = new CustomProperty();
        customProperty.setId(propertyName);
        customProperty.setName(propertyName);
        customProperty.setSimpleValue(propertyValue);
        return customProperty;
    }

    //获取assignee中文名称
    private String getAssigneeName(String key, Map<String, List<ExtensionAttribute>> extensionAttrs){
        String name = "";
        if (extensionAttrs != null && extensionAttrs.size() > 0) {
            List<ExtensionAttribute> extensionAttributeList = extensionAttrs.get(key);
            if (extensionAttributeList != null && extensionAttributeList.size() > 0) {
                name = StringUtils.isEmpty(extensionAttributeList.get(0).getValue()) ? "" : extensionAttributeList.get(0).getValue();
            }
        }
        return  name;
    }

    private String getCandidateValueName(String attrKey, Map<String, List<ExtensionElement>> extensionAttrs, String itemVal){
        String name = "";
        List<Map> valMap = null;
        if (extensionAttrs != null && extensionAttrs.size() > 0) {
            List<ExtensionElement> extensionAttributeList = extensionAttrs.get(attrKey);
            if (extensionAttributeList != null && extensionAttributeList.size() > 0) {
                String attrVal = StringUtils.isEmpty(extensionAttributeList.get(0).getElementText()) ? "" : extensionAttributeList.get(0).getElementText();
                valMap =  com.alibaba.fastjson.JSON.parseArray(attrVal, Map.class);
                if(valMap != null && valMap.size() > 0){
                    for (Map itemMap : valMap) {
                        String val = itemMap.get("value").toString();
                        if(val.contains(itemVal)){
                            name = itemMap.get("name").toString();
                        }
                    }
                }
            }
        }
        return  name;
    }
}
